/**
 * 该文件可自行根据业务逻辑进行调整
 */
import type { RequestClientOptions } from '@vben/request';

import { useAppConfig } from '@vben/hooks';
import { i18n } from '@vben/locales';
import { preferences } from '@vben/preferences';
import {
  authenticateResponseInterceptor,
  defaultResponseInterceptor,
  errorMessageResponseInterceptor,
  RequestClient,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';

import { message } from 'ant-design-vue';
import { Base64 } from 'js-base64';

import { refreshTokenApi } from '#/api/common';
import { router } from '#/router';
import { useAuthStore } from '#/store';

const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);

function createRequestClient(baseURL: string, options?: RequestClientOptions) {
  const client = new RequestClient({
    ...options,
    baseURL,
  });

  /**
   * 重新认证逻辑
   */
  async function doReAuthenticate() {
    console.warn('Access token or refresh token is invalid or expired. ');
    const accessStore = useAccessStore();
    const authStore = useAuthStore();
    accessStore.setAccessToken(null);
    if (
      preferences.app.loginExpiredMode === 'modal' &&
      accessStore.isAccessChecked
    ) {
      accessStore.setLoginExpired(true);
    } else {
      await authStore.logout();
    }
  }

  /**
   * 刷新token逻辑
   */
  async function doRefreshToken() {
    const accessStore = useAccessStore();

    const { token, tenantId, refreshToken, expiration } = await refreshTokenApi(
      {
        refreshToken: accessStore.refreshToken,
      },
    );

    accessStore.setAccessToken(token);
    accessStore.setTenantId(tenantId);
    accessStore.setRefreshToken(refreshToken);
    accessStore.setExpiration(expiration);

    return token;
  }

  function formatToken(token: null | string) {
    return token ? `${token}` : null;
  }

  // 请求头处理
  client.addRequestInterceptor({
    fulfilled: async (config) => {
      const accessStore = useAccessStore();

      config.headers['Accept-Language'] = preferences.app.locale;

      const {
        VITE_GLOB_CLIENT_ID,
        VITE_GLOB_CLIENT_SECRET,
        VITE_GLOB_TOKEN_KEY,
        VITE_GLOB_TENANT_ID_KEY,
        VITE_GLOB_APPLICATION_ID_KEY,
        VITE_GLOB_AUTHORIZATION_KEY,
        VITE_GLOB_GRAY_VERSION,
      } = import.meta.env;

      const token = accessStore.accessToken;
      if (token && !config?.requestOptions?.withoutToken) {
        config.headers[VITE_GLOB_TOKEN_KEY] = formatToken(token);
      }
      if (!config?.requestOptions?.withoutTenant) {
        config.headers[VITE_GLOB_TENANT_ID_KEY] = accessStore.tenantId;
      }

      config.headers[VITE_GLOB_APPLICATION_ID_KEY] = accessStore.applicationId;

      config.headers[VITE_GLOB_AUTHORIZATION_KEY] =
        `${Base64.encode(`${VITE_GLOB_CLIENT_ID}:${VITE_GLOB_CLIENT_SECRET}`)}`;

      // 当前请求地址#号后的路径，需要用户后台判断该页面的数据权限
      config.headers.Path = router?.currentRoute?.value?.fullPath;
      // 当前的多语言
      config.headers.Locale = (i18n.global.locale as any).value;

      // 灰度参数，后台服务集群启动时，可以通过该参数固定请求某个节点！
      config.headers.gray_version = VITE_GLOB_GRAY_VERSION;

      return config;
    },
  });

  // 处理返回的响应数据格式
  client.addResponseInterceptor(
    defaultResponseInterceptor({
      codeField: 'code',
      dataField: 'data',
      successCode: 0,
    }),
  );

  // token过期的处理
  client.addResponseInterceptor(
    authenticateResponseInterceptor({
      client,
      doReAuthenticate,
      doRefreshToken,
      enableRefreshToken: preferences.app.enableRefreshToken,
      formatToken,
    }),
  );

  // 通用的错误处理,如果没有进入上面的错误处理逻辑，就会进入这里
  client.addResponseInterceptor(
    errorMessageResponseInterceptor((msg: string, error) => {
      // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理，根据不同的 code 做不同的提示，而不是直接使用 message.error 提示 msg
      // 当前mock接口返回的错误字段是 error 或者 message
      const responseData = error?.response?.data ?? {};
      const errorMessage = responseData?.error ?? responseData?.msg ?? '';
      // 如果没有错误信息，则会根据状态码进行提示
      message.error(errorMessage || msg);
    }),
  );

  return client;
}

export const requestClient = createRequestClient(apiURL, {
  responseReturn: 'data',
});

export const baseRequestClient = new RequestClient({ baseURL: apiURL });
